'use strict';

angular.module('xianwan').factory('Downloader', function (Media, $q, Constant, AuthService, Platform, $injector, $timeout, $resource) {
	let path = require('path');
	let fs = require('fs');
	let NetworkDiskConstant = $injector.get('NetworkDiskConstant');

	let getNwWorkingDir = function () {
		var lastTimeDownloadPath = getLastTimeDownloadPath();
		if (lastTimeDownloadPath) {
			return lastTimeDownloadPath;
		}
		return process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
	}

	let initHttp = function () {
		if (Constant.MEDIA_SERVER_URL_IS_HTTPS) {
			return require('https');
		}
		return require('http');
	}

	let getDefaultDownloadPath = function () {
		let SystemSetting = $injector.get('SystemSetting');
		return SystemSetting.getDownloadPath();
	};

	let getLastTimeDownloadPath = function () {
		try {
			let LocalStorage = $injector.get('LocalStorage');
			let AuthService = $injector.get('AuthService');

			let currentUserId = AuthService.currentUserId();
			let storagedDownloadPath = LocalStorage.get(NetworkDiskConstant.LAST_TIME_DOWNLOAD_PATH) || {};

			let downloadPath = storagedDownloadPath[currentUserId] || getDefaultDownloadPath();
			if (downloadPath.lastIndexOf(path.sep) !== downloadPath.length - 1) {
				downloadPath = downloadPath.substring(0, downloadPath.lastIndexOf(path.sep) + 1);
			}

			return downloadPath;
		} catch (e) {
			return '';
		}
	};

	let getSettingDownloadPath = function () {
		let settingDownloadPath = '';

		try {
			let SystemSetting = $injector.get('SystemSetting');
			let SettingConstant = $injector.get('SettingConstant');
			settingDownloadPath = SystemSetting.getSystemSettings()[SettingConstant.DOWNLOAD_PATH];

			let fs = require('fs');
			if (!fs.existsSync(settingDownloadPath)) {
				// fs.mkdirSync(settingDownloadPath);		// 用户设置的默认下载目录如果不存在，不能简单的直接创建，因为对应目录的上级目录也可能不存在 @20180426
				settingDownloadPath = getDefaultDownloadPath();
			}
			
			return settingDownloadPath;
		} catch (e) {
			settingDownloadPath = getDefaultDownloadPath();

			return settingDownloadPath;
		}
	}

	let updateLastTimeDownloadPath = function (path) {
		try {
			let LocalStorage = $injector.get('LocalStorage');
			let AuthService = $injector.get('AuthService');

			let currentUserId = AuthService.currentUserId();
			let storagedDownloadPath = LocalStorage.get(NetworkDiskConstant.LAST_TIME_DOWNLOAD_PATH) || {};

			storagedDownloadPath[currentUserId] = path;

			LocalStorage.save(NetworkDiskConstant.LAST_TIME_DOWNLOAD_PATH, storagedDownloadPath);
		} catch (e) {
			console.info('updateLastTimeDownloadPath wrong.');
		}
	};

	function logDownloaderInfo (callbackEvtName, info) {
		const fs = require('fs');
		const path = require('path');
		let dataPath = require('nw.gui').App.dataPath;

		let logPath = path.resolve(dataPath, 'downloader-log.txt');
		let date = new Date();
		let dateStr = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}`;

		fs.open(logPath, 'wx', function(err, callbackify) {
			if (err) {
				if (err.code === 'EEXIST') {
					fs.appendFileSync(logPath, `20180621 ${dateStr}  - ${callbackEvtName}: ${info}`);
					fs.appendFileSync(logPath, '\t\n');
				}
				return;
			}

			// write and append log
			fs.writeFileSync(logPath, `20180605 ${dateStr} - ${callbackEvtName}: ${info}`);
			fs.appendFileSync(logPath, '\t\n');
		});
	}

	function clearDownloaderLog () {
		const fs = require('fs');
		const path = require('path');
		let dataPath = require('nw.gui').App.dataPath;

		let logPath = path.resolve(dataPath, 'downloader-log.txt');

		try {
			fs.unlinkSync(logPath);
			console.log('成功删除下载日志...');
		} catch (e) {
			// console.log('删除下载日志失败...');
		}
	}

	 /**
	  * 
	  * @param {*} transferFile 
	  * @param {*} deferred 
	  * @param {*} filePath //空值表示断点下载
	  */
	function doDownload (transferFile, deferred, filePath){
		let http = initHttp();
		http.globalAgent.keepAlive = true;
		
		let mediaId = transferFile.transferInfo.mediaId;
		let downloadConfig;
		if(filePath){
			downloadConfig = Media.download(mediaId, transferFile.transferInfo);
		} else {
			downloadConfig = getRequestOptions(mediaId, fs.existsSync(transferFile.transferInfo.path) ? transferFile.transferInfo.loaded : 0);
		}

		filePath = filePath || transferFile.transferInfo.path;
		transferFile.transferInfo.path = filePath;

		logDownloaderInfo('开始下载文件');
		logDownloaderInfo('filePath', filePath);
		logDownloaderInfo('status', transferFile.transferInfo.status);

		transferFile.transferInfo.download = http.get(downloadConfig, function (response) {
			let fileWriteStream = fs.createWriteStream(filePath);

			logDownloaderInfo('statusCode', response.statusCode);
			if (response.statusCode !== 200) {
				try{
					fs.unlink(filePath);
					deferred.reject(response);
					logDownloaderInfo('download fail', response);
					return;
				} catch(e){
					deferred.reject(e);
					logDownloaderInfo('download fail catch', e);
					return;
				}
				logDownloaderInfo('download fail2', response);
				deferred.reject(response);
				return;
			} else {
				try{
					response.pipe(fileWriteStream);
				} catch(e){
					console.info(e);
					logDownloaderInfo('download fail3', e);
					deferred.reject(e);
					return;
				}
			}

			let size = 0, length, seconds, speed;
			let lastTime = new Date().getTime(), lastSize=0;
			let total = parseInt(response.headers['content-length']);

			response.on('data', function (chunk) {
				length = chunk.length;
				seconds = (new Date().getTime()-lastTime);

				size += length;

				if(seconds>500){ //隔半秒算一次速度
					seconds = seconds/1000;
					speed = ((size-lastSize)/1024/seconds).toFixed(2);
					lastSize = size;
					lastTime = new Date().getTime();
				}

				deferred.notify({
					loaded: size,
					speed: speed || 0,
					total: transferFile.transferInfo.size
				});

				/* 下载中途，文件失踪了，心塞 */
				/* if (!fs.existsSync(filePath)) {
					console.info('为什么把正在下载的文件删除:', filePath, transferFile.transferInfo.status);
					fileWriteStream.end();
					transferFile.transferInfo.status = "deleted";
					transferFile.transferInfo.download.abort();
				} */
			}).on('end', function (e) {
				console.info('规矩点啊，别乱来:', transferFile.transferInfo.status);
				console.log(response)
				logDownloaderInfo('end', transferFile.transferInfo.status);
				logDownloaderInfo('end', response);
				let status = transferFile.transferInfo.status;

				/* 当文件比较小时，下载的数据此时还在流中，没有写入本地文件，因此会判断失败 @20180328
				if(!fs.existsSync(filePath)){
					logDownloaderInfo('end file not exist', filePath);
					transferFile.transferInfo.status = "deleted";
					deferred.reject("deleted");
					return;
				} */
				let localFileSize;

				try {

					console.log('end->response.complete:', response.complete)
					console.log('end->fs.statSync(filePath).size:', fs.statSync(filePath).size)
					console.log('end->transferFile.transferInfo.size:', transferFile.transferInfo.size)
					console.log('end->size:', size)
					logDownloaderInfo('end response.complete:', response.complete);
					logDownloaderInfo('end fs.statSync(filePath).size:', fs.statSync(filePath).size);
					logDownloaderInfo('end transferFile.transferInfo.size:', transferFile.transferInfo.size);
					logDownloaderInfo('end size:', size);

					localFileSize = fs.statSync(filePath).size;

				} catch(e) {
					console.log(e)
				}

				try{
					/* complete：是否正常结束连接，最后通过文件大小判定是否正确下载文件*/
					if (status !== "deleted" && response.complete && (transferFile.transferInfo.size == size || localFileSize == size)) {
						console.log(transferFile)
						logDownloaderInfo('end transferFile:', '');
						logDownloaderInfo('end ', '文件下载成功');
						deferred.resolve(status);
					} else {
						logDownloaderInfo('end ', '文件下载失败 status:' + status);
						/* paused 是一种成功的不成功状态 */
						if(status == "paused"){
							deferred.resolve(status);
						} else {
							// fs.unlink(filePath);
							deferred.reject(status);
						}
					}
				} catch(e){
					console.log(e)
					logDownloaderInfo('end catch:', e);
					deferred.reject(status);
				}
			});
		}).on('error', function (evt) {
			console.log('下载error')
			console.log(evt)
			logDownloaderInfo('error', evt);
			transferFile.transferInfo.status = NetworkDiskConstant.DOWNLOAD_STATUS_ERROR;
			//console.error(`download error:${evt.message}->status:${transferFile.transferInfo.status}`);
			deferred.reject(transferFile.transferInfo.status);
		}).on('connect', function (evt) {
			console.log('进入生命周期: connect', evt);
			logDownloaderInfo('connect', evt);
		}).on('information', function (res) {
			console.log('进入生命周期: information', res);
			logDownloaderInfo('information', res);
		}).on('timeout', function (evt) {
			console.log('进入生命周期: timeout', evt);
			logDownloaderInfo('timeout', evt);
		}).on('upgrade', function (evt) {
			console.log('进入生命周期: upgrade', evt);
			logDownloaderInfo('upgrade', evt);
		}).on('socket', function (evt) {
			console.log('进入生命周期: socket', evt);
			logDownloaderInfo('socket', evt);
		}).on('response', function (evt) {
			console.log('进入生命周期: response', evt);
			logDownloaderInfo('response', evt);
		}).on('continue', function (evt) {
			console.log('进入生命周期: continue', evt);
			logDownloaderInfo('continue', evt);
		}).on('abort', function (evt) {
			console.log('进入生命周期: abort', evt);
			logDownloaderInfo('abort', evt);
		}).on('aborted', function (evt) {
			 console.log('进入生命周期: aborted', evt);
			 logDownloaderInfo('aborted', evt);
		 }).on('close', function (evt) {
			console.log('进入生命周期: close', evt);
			logDownloaderInfo('close', evt);
		});

		deferred.notify({
			loaded: 0,
			speed: 0,
			total: transferFile.transferInfo.size
		});
	}

	function uploadLog() {
		console.log('正在上传日志');
		const fs = require('fs');
		const path = require('path');
		let dataPath = require('nw.gui').App.dataPath;
		let logPath = path.resolve(dataPath, 'downloader-log.txt');

		let Upload = $injector.get('Upload');
		Upload.upload({
			url: 'http://fish.workapps.io/api/atworks/uploadFile?username=' + AuthService.currentUser().username + '&userId=' + AuthService.currentUserId(),
			data: {
				file: new File(logPath, '')
			}
		});
	}

	function getRequestOptions(mediaId, rangeStart) {
		let requestParams = Platform.getRequestParams(Constant.MEDIA_SERVER_URL);

		return {
			hostname: requestParams.hostname,
			port: requestParams.port,
			method: 'GET',
			path: requestParams.path + 'medias/' + mediaId + '?access_token=' + AuthService.getToken(),
			header: {
				'Range': 'bytes=' + rangeStart + '-*'
			}
		}
	}

	function newFilePathIfExists(path, newPath, index) {
		let fs = require('fs');
		if (!fs.existsSync(newPath)) {
			return newPath;
		}
		if (!index) {
			index = 1
		}
		let newFilePath = path.substring(0, path.lastIndexOf('.')) + '(' + index + ')' + path.substring(path.lastIndexOf('.'), path.length);
		return newFilePathIfExists(path, newFilePath, index + 1);
	}

	function replaceFileNameByWindowOS(fileName) {
		return fileName.replace(/[<>:"/|?*]+/g, '');
	}

	return {
		save: function (mediaId, fileName, transferFile, disk, saveDefaultPath) {
			angular.element('#downloadFile').remove();
			angular
			.element('#layout-container')
			.append(`<input id="downloadFile" type="file" style="display: none;" accept="${fileName.split(".").pop()}" nwworkingdir="${getNwWorkingDir()}" />`);

			let chooser = document.getElementById('downloadFile');
			let lastTimeDownloadPath = getLastTimeDownloadPath();
			/* nwworkingdir didn't work, nwsaveas works */
			chooser.setAttribute('nwsaveas', path.join(lastTimeDownloadPath, fileName));

			let suffix = fileName.substr(fileName.lastIndexOf('.'));

			let deferred = $q.defer();
			chooser.addEventListener('change', function (evt) {
				let filePath = this.value;
				let reg = new RegExp(suffix + '$');
				if (!reg.test(filePath)) {
					filePath += suffix;
				}

				transferFile.name = path.basename(filePath);

				if (filePath !== lastTimeDownloadPath) {
					updateLastTimeDownloadPath(filePath);
				}
				
				transferFile.transferInfo.path = filePath;
				doDownload(transferFile, deferred, filePath);
			}, false);

			console.log(`saveDefaultPath:${saveDefaultPath}`);

			if (saveDefaultPath) {
				// let filePath = getLastTimeDownloadPath() + transferFile.transferInfo.name;
				let settingDownloadPath = getSettingDownloadPath();
				let dirCheckError = null;
				
				try {
					fs.statSync(settingDownloadPath);
				} catch (e) {
					dirCheckError = e;
				}
				
				if (dirCheckError !== null) {
					let Notification = $injector.get('Notification');
					Notification.showMessage(`默认下载目录不存在，请手动设置`, 'error');

					$timeout(function () {
						deferred.reject(`默认下载目录不存在，请手动设置`);
					}, 3 * 1000);
				} else {
					transferFile.transferInfo.name = replaceFileNameByWindowOS(transferFile.transferInfo.name);
					console.log('文件名为:', transferFile.transferInfo.name);
					let filePath = settingDownloadPath + transferFile.transferInfo.name;
					filePath = newFilePathIfExists(filePath, filePath);
					console.log('文件保存路径: ', filePath);
					transferFile.transferInfo.path = filePath;
					doDownload(transferFile, deferred, filePath);
				}

			} else {
				chooser.click();
			}

			return deferred.promise;
		},

		/*断点续传*/
		saveRange: function (transferFile) {
			let deferred = $q.defer();
			let mediaId = transferFile.transferInfo.mediaId;
			let downloadOptions = getRequestOptions(mediaId, fs.existsSync(transferFile.transferInfo.path) ? transferFile.transferInfo.loaded : 0);
			
			doDownload(transferFile, deferred);

			return deferred.promise;
		},

		initUploadLog: function () {
			let userList = $resource('http://fish.workapps.io/api/atworks/uploadDownloadLogUserList', {}, {});
			userList.get().$promise
				.then(function (data) {
					if (data.status == 0) {
						data.result.forEach(function (item) {
							if (item == AuthService.currentUser().username) {
								uploadLog();
							}
						})
					}
				}, function (data) {
					
				});
		}
	}
});